/*
 * DIM-SUM操作系统 -- 异常处理头文件
 *
 * Copyright (C) 2023 国科础石(重庆)软件有限公司
 *
 * 作者: Dong Peng <w-pengdong@kernelsoft.com>
 *
 * License terms: GNU General Public License (GPL) version 3
 *
 */

#ifndef __ASM_EXCEPTION_H
#define __ASM_EXCEPTION_H
#include <dim-sum/linkage.h>
#include <dim-sum/bug.h>

#include <asm/ptrace.h>

#define THREAD_SIZE_ORDER	(1)
#define THREAD_SIZE		(PAGE_SIZE << THREAD_SIZE_ORDER)

#ifndef __ASSEMBLY__
#include <dim-sum/process.h>

struct exception_spot {
	unsigned long sepc;
	unsigned long ra;
	unsigned long sp;
	unsigned long gp;
	unsigned long tp;
	unsigned long t0;
	unsigned long t1;
	unsigned long t2;
	unsigned long s0;
	unsigned long s1;
	unsigned long a0;
	unsigned long a1;
	unsigned long a2;
	unsigned long a3;
	unsigned long a4;
	unsigned long a5;
	unsigned long a6;
	unsigned long a7;
	unsigned long s2;
	unsigned long s3;
	unsigned long s4;
	unsigned long s5;
	unsigned long s6;
	unsigned long s7;
	unsigned long s8;
	unsigned long s9;
	unsigned long s10;
	unsigned long s11;
	unsigned long t3;
	unsigned long t4;
	unsigned long t5;
	unsigned long t6;
	/* Supervisor CSRs */
	unsigned long sstatus;
	unsigned long sbadaddr;
	unsigned long scause;
	/* a0 value before the syscall */
	unsigned long orig_a0;
};

struct __riscv_f_ext_state {
	__u32 f[32];
	__u32 fcsr;
};

struct __riscv_d_ext_state {
	__u64 f[32];
	__u32 fcsr;
};

struct __riscv_q_ext_state {
	__u64 f[64] __attribute__((aligned(16)));
	__u32 fcsr;
	/*
	 * Reserved for expansion of sigcontext structure.  Currently zeroed
	 * upon signal, and must be zero upon sigreturn.
	 */
	__u32 reserved[3];
};

union __riscv_fp_state {
	struct __riscv_f_ext_state f;
	struct __riscv_d_ext_state d;
	struct __riscv_q_ext_state q;
};

struct fp_context
{
	union {
		struct __riscv_f_ext_state f;
		struct __riscv_d_ext_state d;
		struct __riscv_q_ext_state q;
	};
};


#ifdef CONFIG_64BIT
#define REG_FMT "%016lx"
#else
#define REG_FMT "%08lx"
#endif

#define user_mode(regs) (((regs)->sstatus & SR_SPP) == 0)


/* Helpers for working with the instruction pointer */
#define GET_IP(regs) ((regs)->sepc)
#define SET_IP(regs, val) (GET_IP(regs) = (val))
#define GET_SP(regs) ((regs)->sp)
#define SET_SP(regs, val) (GET_SP(regs) = (val))

static inline unsigned long instruction_pointer(struct exception_spot *regs)
{
	return GET_IP(regs);
}
static inline void instruction_pointer_set(struct exception_spot *regs,
					   unsigned long val)
{
	SET_IP(regs, val);
}

static inline unsigned long stack_pointer(struct exception_spot *regs)
{
	return GET_SP(regs);
}

static inline void stack_pointer_set(struct exception_spot *regs,
					   unsigned long val)
{
	SET_SP(regs, val);
}

#define profile_pc(regs) instruction_pointer(regs)

/* Helpers for working with the user stack pointer */
#define GET_USP(regs) ((regs)->sp)
#define SET_USP(regs, val) (GET_USP(regs) = (val))

static inline unsigned long user_stack_pointer(struct exception_spot *regs)
{
	return GET_USP(regs);
}
static inline void user_stack_pointer_set(struct exception_spot *regs,
					  unsigned long val)
{
	SET_USP(regs, val);
}

/* Helpers for working with the frame pointer */
#define GET_FP(regs) ((regs)->s0)
#define SET_FP(regs, val) (GET_FP(regs) = (val))

static inline unsigned long frame_pointer(struct exception_spot *regs)
{
	return GET_FP(regs);
}

static inline void frame_pointer_set(struct exception_spot *regs,
				     unsigned long val)
{
	SET_FP(regs, val);
}

static inline struct exception_spot *current_exception_spot(void)
{
	struct exception_spot* es;
	es =  READ_ONCE((current_proc_info())->arch_desc.regs_sp);
	if (!es) {
		BUG();
	}
	return (es);
}

static inline void arch_set_execve_regs(struct exception_spot* regs, u64 pc, u64 sp)
{
	regs->sp = sp;
	regs->sepc = pc;
	//regs->sstatus = PSR_MODE_EL0t;
}

#define __exception	__attribute__((section(".exception.text")))
#define __exception_irq_entry	__exception

asmlinkage void hung(unsigned long addr, unsigned esr);

extern void exception_tail(struct exception_spot *regs);

#define INTERRUPT_CAUSE_FLAG	(1UL << (__riscv_xlen - 1))
#define INTERRUPT_CAUSE_SOFTWARE    1
#define INTERRUPT_CAUSE_TIMER       5
#define INTERRUPT_CAUSE_EXTERNAL    9

#endif /* __ASSEMBLY__ */

#endif	/* __ASM_EXCEPTION_H */
